//
//  SmallVideoViewController.m
//  ImagePicker
//
//  Created by YH on 2018/4/26.
//  Copyright © 2018年 王跃. All rights reserved.
//

#import <AVFoundation/AVFoundation.h>
#import "SmallVideoViewController.h"
#import "LoopProgressView.h"
#import "SmallVideoConfig.h"
#import "ShowVideoViewController.h"

#define ActionViewWidth     80.f
#define ActionViewHeight    80.f
#define ItemSpace           10.f
#define DeviceSpcace        10.f
#define DeviceWith          (SmallVideoSCREEN_WIDTH + 10)
#define DeviceHeight        (SmallVideoSCREEN_HEIGHT + 16)

@interface SmallVideoViewController ()<AVCaptureVideoDataOutputSampleBufferDelegate,
                                       AVCaptureAudioDataOutputSampleBufferDelegate,
                                       LoopProgressViewDelegate>

{
    dispatch_queue_t    _recoding_queue;
}

@property (nonatomic, strong) UIView                                 *videoView;
@property (nonatomic, strong) AVCaptureSession                       *videoSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer             *videoPreLayer;
@property (nonatomic, strong) AVCaptureDevice                        *videoDevice;
@property (nonatomic, strong) AVCaptureVideoDataOutput               *videoDataOut;
@property (nonatomic, strong) AVCaptureAudioDataOutput               *audioDataOut;
@property (nonatomic, strong) AVAssetWriter                          *assetWriter;
@property (nonatomic, strong) AVAssetWriterInputPixelBufferAdaptor   *assetWriterPixelBufferInput;
@property (nonatomic, strong) AVAssetWriterInput                     *assetWriterVideoInput;
@property (nonatomic, strong) AVAssetWriterInput                     *assetWriterAudioInput;
@property (nonatomic, strong) UIButton                               *backRecodeButton;
@property (nonatomic, strong) UIButton                               *completeButton;
@property (nonatomic, strong) UIButton                               *turnButton;
@property (nonatomic, strong) AVPlayerLayer                          *playerLayer;
@property (nonatomic, strong) AVPlayer                               *player;
@property (nonatomic, assign) BOOL                                   recoding;
@property (nonatomic, strong) LoopProgressView                       *loopProgressView;
@property (nonatomic, strong) SmallVideoModel                        *smallVideoModel;
@property (nonatomic, strong) ShowVideoViewController                *smallVideoPlayVC;
@end

@implementation SmallVideoViewController
{
   CMTime   _currentSampleTime;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setupUI];
    [self setupVideo];
    [self initNotification];
}

#pragma mark  初始化UI

- (void)setupUI
{
    self.videoView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, DeviceWith, DeviceHeight)];
    self.videoView.backgroundColor = [UIColor clearColor];
    self.videoView.center = CGPointMake((DeviceWith)/ 2,
                                                    (DeviceHeight) / 2);
    [self.view addSubview:self.videoView];

    self.smallVideoPlayVC = [[ShowVideoViewController alloc] init];
    [self addChildViewController:self.smallVideoPlayVC];
    self.smallVideoPlayVC.view.frame = CGRectMake(0, 0, DeviceWith, DeviceHeight);
    self.smallVideoPlayVC.view.hidden = YES;
    self.smallVideoPlayVC.view.center = CGPointMake((DeviceWith)/ 2,
                                                    (DeviceHeight) / 2);
    [self.view addSubview:self.smallVideoPlayVC.view];

    self.turnButton = [UIButton buttonWithType:UIButtonTypeCustom];
    self.turnButton.frame = CGRectMake(SmallVideoSCREEN_WIDTH - 80, 35, 50, 50);
    self.turnButton.backgroundColor = [UIColor blueColor];
    self.turnButton.layer.cornerRadius = 25.f;
    self.turnButton.layer.masksToBounds = YES;
    self.turnButton.titleLabel.font = [UIFont systemFontOfSize:15.f];
    [self.turnButton setTitle:@"前置" forState:UIControlStateNormal];
    [self.turnButton addTarget:self action:@selector(respondsToButton) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.turnButton];

    self.backRecodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
    self.backRecodeButton.frame = CGRectMake(-ActionViewWidth, SmallVideoSCREEN_HEIGHT - 100 - ActionViewHeight, ActionViewWidth, ActionViewHeight);
    self.backRecodeButton.backgroundColor = [UIColor blueColor];
    self.backRecodeButton.layer.cornerRadius = ActionViewHeight/2;
    self.backRecodeButton.layer.masksToBounds = YES;
    [self.backRecodeButton setTitle:@"返回" forState:UIControlStateNormal];
    [self.backRecodeButton addTarget:self action:@selector(respondsToBackRecodeButton) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.backRecodeButton];

    self.completeButton = [UIButton buttonWithType:UIButtonTypeCustom];
    self.completeButton.frame = CGRectMake(SmallVideoSCREEN_WIDTH + ActionViewWidth, SmallVideoSCREEN_HEIGHT - 100 - ActionViewHeight, ActionViewWidth, ActionViewHeight);
    self.completeButton.backgroundColor = [UIColor redColor];
    self.completeButton.layer.cornerRadius = ActionViewHeight/2;
    self.completeButton.layer.masksToBounds = YES;
    [self.completeButton setTitle:@"完成" forState:UIControlStateNormal];
    [self.completeButton addTarget:self action:@selector(respondsToCompleteButton) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.completeButton];

    self.loopProgressView = [[LoopProgressView alloc] initWithFrame:CGRectMake(SmallVideoSCREEN_WIDTH / 2 - ActionViewWidth/2, SmallVideoSCREEN_HEIGHT - 100 - ActionViewHeight, ActionViewWidth, ActionViewHeight)];
    self.loopProgressView.delegate = self;
    self.loopProgressView.layer.cornerRadius = ActionViewHeight/2;
    self.loopProgressView.layer.masksToBounds = YES;
    [self.view addSubview:self.loopProgressView];
}

#pragma mark  注册通知

- (void)initNotification
{
    // 添加播放完成通知
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(playDidEnd)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:self.player];
}

#pragma mark  通知事件

- (void)playDidEnd
{
    __weak typeof(self) waekSelf = self;
    [self.player seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
        [waekSelf.player play];
    }];
}

#pragma mark  初始化视频录制

- (void)setupVideo
{
    NSString *errorString = nil;
    if (TARGET_IPHONE_SIMULATOR) {
        errorString = @"模拟器不可用";
    }

    AVAuthorizationStatus videoAuthStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if (videoAuthStatus == AVAuthorizationStatusRestricted || videoAuthStatus == AVAuthorizationStatusDenied) {
         errorString = @"相机访问受限";
    }

    AVAuthorizationStatus audioAuthStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
    if (audioAuthStatus == AVAuthorizationStatusRestricted || videoAuthStatus == AVAuthorizationStatusDenied) {
        errorString = @"录音访问受限";
    }

    _recoding_queue = dispatch_queue_create("com.SmallVideoSky", DISPATCH_QUEUE_SERIAL);

    self.videoDevice = [self cameraWithPostion:(AVCaptureDevicePositionBack)];

    NSArray *devicesAudio = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
    AVCaptureInput *backVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:self.videoDevice error:nil];;
    AVCaptureInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:[devicesAudio firstObject] error:nil];

    self.videoDataOut = [[AVCaptureVideoDataOutput alloc] init];
    self.videoDataOut.videoSettings = @{(__bridge NSString *)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_32BGRA)};
    self.videoDataOut.alwaysDiscardsLateVideoFrames = YES;
    [self.videoDataOut setSampleBufferDelegate:self queue:_recoding_queue];

    self.audioDataOut = [[AVCaptureAudioDataOutput alloc] init];
    [self.audioDataOut setSampleBufferDelegate:self queue:_recoding_queue];

    self.videoSession = [[AVCaptureSession alloc] init];

    if ([self.videoSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
        self.videoSession.sessionPreset = AVCaptureSessionPreset640x480;
    }

    if ([self.videoSession canAddInput:backVideoInput]) {
        [self.videoSession addInput:backVideoInput];
    }

    if ([self.videoSession canAddInput:audioInput]) {
        [self.videoSession addInput:audioInput];
    }

    if ([self.videoSession canAddOutput:self.videoDataOut]) {
        [self.videoSession addOutput:self.videoDataOut];
    }

    if ([self.videoSession canAddOutput:self.audioDataOut]) {
        [self.videoSession addOutput:self.audioDataOut];
    }

    self.videoPreLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.videoSession];
    self.videoPreLayer.frame = CGRectMake(0,
                                          0,
                                          DeviceWith,
                                          DeviceHeight);

    self.videoPreLayer.position = CGPointMake((DeviceWith)/ 2,
                                              (DeviceHeight) / 2);

    self.videoPreLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.videoView.layer addSublayer:self.videoPreLayer];
    [self.videoSession startRunning];
}

#pragma mark  点击事件

- (void)respondsToButton
{
    NSArray *inputs =self.videoSession.inputs;
    for (AVCaptureDeviceInput *input in inputs ) {

        AVCaptureDevice *device = input.device;
        if ( [device hasMediaType:AVMediaTypeVideo] ) {
            AVCaptureDevicePosition position = device.position;
            AVCaptureDevice *newCamera =nil;
            AVCaptureDeviceInput *newInput =nil;

            if (position ==AVCaptureDevicePositionFront){
                newCamera = [self cameraWithPostion:AVCaptureDevicePositionBack];
            }else{
                newCamera = [self cameraWithPostion:AVCaptureDevicePositionFront];
            }

            newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
            [self.videoSession beginConfiguration];
            [self.videoSession removeInput:input];
            [self.videoSession addInput:newInput];
            [self.videoSession commitConfiguration];
            break;
        }
    }
}

- (void)respondsToBackRecodeButton
{
    self.turnButton.hidden = NO;
    self.videoView.hidden = NO;
    self.smallVideoPlayVC.view.hidden = YES;
    [self.smallVideoPlayVC removePlayLayer];

    CGRect backRecodeButtonFrame = self.backRecodeButton.frame;
    CGRect completeButtonFrame = self.completeButton.frame;

    backRecodeButtonFrame.origin.x = -ActionViewWidth;
    completeButtonFrame.origin.x = SmallVideoSCREEN_WIDTH + ActionViewWidth;

    [UIView animateWithDuration:0.5f animations:^{
        self.backRecodeButton.frame = backRecodeButtonFrame;
        self.completeButton.frame = completeButtonFrame;
    } completion:^(BOOL finished) {
        self.loopProgressView.hidden = NO;
    }];
}

- (void)respondsToCompleteButton
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark  自定义事件

- (AVCaptureDevice *)cameraWithPostion:(AVCaptureDevicePosition)position
{
    AVCaptureDeviceDiscoverySession *deviceDiscoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:position];
    NSArray *devices = deviceDiscoverySession.devices;
    for (AVCaptureDevice *device in devices) {
        if ([device position] == position) {
            return device;
        }
    }
    return nil;
}

- (void)recodeDidEndAnimation
{
    self.loopProgressView.hidden = YES;

    CGRect backRecodeButtonFrame = self.backRecodeButton.frame;
    CGRect completeButtonFrame = self.completeButton.frame;

    backRecodeButtonFrame.origin.x = CGRectGetMinX(self.loopProgressView.frame) - ItemSpace - ActionViewWidth;
    completeButtonFrame.origin.x = CGRectGetMaxX(self.loopProgressView.frame) + ItemSpace;

    [UIView animateWithDuration:0.5f animations:^{
        self.backRecodeButton.frame = backRecodeButtonFrame;
        self.completeButton.frame = completeButtonFrame;
    } completion:^(BOOL finished) {
        [self.loopProgressView removeCircleShapeLayer];
    }];
}

#pragma mark  LoopProgressViewDelegate

- (void)loopProgressViewRecordedState:(LoopProgressViewState)loopProgressViewState
{
    if (loopProgressViewState == LoopProgressViewStateBegin) {
        self.turnButton.hidden = YES;
        if ([SmallVideoUtils existVideo]) {
            [SmallVideoUtils deleteVideo:self.smallVideoModel.videoAbsolutePath];
        }
        self.smallVideoModel = [SmallVideoUtils createNewVideo];
        [self createWriter:[NSURL fileURLWithPath:self.smallVideoModel.videoAbsolutePath]];

        self.recoding = YES;
    }else if (loopProgressViewState == LoopProgressViewStateEnd){
        self.recoding = NO;
        [self recodeDidEndAnimation];
        __weak typeof(self) weakSelf = self;
        [self saveVideo:^(NSURL *outFileURL) {
            if (weakSelf.smallVideoModel && self.smallVideoModel.videoAbsolutePath) {
                weakSelf.videoView.hidden = YES;
                weakSelf.smallVideoPlayVC.url = outFileURL;
                weakSelf.smallVideoPlayVC.view.hidden = NO;
            }
        }];
    }else if (loopProgressViewState == LoopProgressViewStateCancel){
        self.recoding = NO;
    }
}

#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioDataOutputSampleBufferDelegate

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

    if (!self.recoding) return;

    @autoreleasepool {
        _currentSampleTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer);
        if (self.assetWriter.status != AVAssetWriterStatusWriting) {
            [self.assetWriter startWriting];
            [self.assetWriter startSessionAtSourceTime:_currentSampleTime];
        }

        if (captureOutput == self.videoDataOut) {
            if (self.assetWriterPixelBufferInput.assetWriterInput.isReadyForMoreMediaData) {
                CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
                BOOL success = [self.assetWriterPixelBufferInput appendPixelBuffer:pixelBuffer withPresentationTime:_currentSampleTime];
                if (!success) {
                    NSLog(@"PixelBufferInput没有append成功!");
                }
            }

        }
        if (captureOutput == self.audioDataOut) {
             [self.assetWriterAudioInput appendSampleBuffer:sampleBuffer];
        }
    }
}

- (void)captureOutput:(AVCaptureOutput *)captureOutput didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

}

- (void)createWriter:(NSURL *)assetUrl
{
    self.assetWriter = [AVAssetWriter assetWriterWithURL:assetUrl fileType:AVFileTypeMPEG4 error:nil];
    int videoWidth = SmallVideoSCREEN_WIDTH + 16;
    int videoHeight = SmallVideoSCREEN_HEIGHT + 16;

    NSDictionary *outputSettings = @{
                                     AVVideoCodecKey : AVVideoCodecH264,
                                     AVVideoWidthKey : @(videoHeight),
                                     AVVideoHeightKey : @(videoWidth),
                                     AVVideoScalingModeKey:AVVideoScalingModeResizeAspectFill,
                                     //                          AVVideoCompressionPropertiesKey:codecSettings
                                     };
    self.assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
    self.assetWriterVideoInput.expectsMediaDataInRealTime = YES;
    self.assetWriterVideoInput.transform = CGAffineTransformMakeRotation(M_PI / 2.0);

    NSDictionary *audioOutputSettings = @{
                                          AVFormatIDKey:@(kAudioFormatMPEG4AAC),
                                          AVEncoderBitRateKey:@(64000),
                                          AVSampleRateKey:@(44100),
                                          AVNumberOfChannelsKey:@(1),
                                          };

    self.assetWriterAudioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioOutputSettings];
    self.assetWriterAudioInput.expectsMediaDataInRealTime = YES;

    NSDictionary *SPBADictionary = @{
                                     (__bridge NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32ARGB),
                                     (__bridge NSString *)kCVPixelBufferWidthKey : @(videoWidth),
                                     (__bridge NSString *)kCVPixelBufferHeightKey  : @(videoHeight),
                                     (__bridge NSString *)kCVPixelFormatOpenGLESCompatibility : ((__bridge NSNumber *)kCFBooleanTrue)
                                     };
    self.assetWriterPixelBufferInput = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:self.assetWriterVideoInput sourcePixelBufferAttributes:SPBADictionary];
    if ([self.assetWriter canAddInput:self.assetWriterVideoInput]) {
        [self.assetWriter addInput:self.assetWriterVideoInput];
    }else {
        NSLog(@"不能添加视频writer的input\(assetWriterVideoInput)");
    }
    if ([self.assetWriter canAddInput:self.assetWriterAudioInput]) {
        [self.assetWriter addInput:self.assetWriterAudioInput];
    }else {
        NSLog(@"不能添加视频writer的input\(assetWriterVideoInput)");
    }
}

- (void)saveVideo:(void(^)(NSURL *outFileURL))complier {

    if (self.recoding) return;

    if (!_recoding_queue){
        complier(nil);
        return;
    };

    dispatch_async(_recoding_queue, ^{
        NSURL *outputFileURL = [NSURL fileURLWithPath:self.smallVideoModel.videoAbsolutePath];
        if (self.assetWriter.status == AVAssetWriterStatusWriting) {
            [self.assetWriter finishWritingWithCompletionHandler:^{

                if (self.recoding) return ;

              UIImage *image = [SmallVideoUtils saveThumImageWithVideoURL:outputFileURL second:1];

                if (complier) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (image != nil) {
                            self.smallVideoPlayVC.image = image;
                        }
                        complier(outputFileURL);
                        NSLog(@"%.2f", [self fileSizeAtPath:self.smallVideoModel.videoAbsolutePath]);
                    });
                }
            }];
        }

    });

}

- (CGFloat) fileSizeAtPath:(NSString*)filePath
{
    NSFileManager* manager = [NSFileManager defaultManager];
    if ([manager fileExistsAtPath:filePath])
    {
        return [[manager attributesOfItemAtPath:filePath error:nil] fileSize] / 1024.0;
    }
    return 0;
}

@end
